package com.distribution.system.manager.channel;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.distribution.common.core.redis.RedisCache;
import com.distribution.common.exception.ServiceException;
import com.distribution.common.utils.StringUtils;
import com.distribution.common.utils.spring.SpringUtils;
import com.distribution.system.domain.bo.AddressInfoBo;
import com.distribution.system.domain.bo.AddressNameBo;
import com.distribution.system.domain.bo.CmccDaUpChannelInfoBO;
import com.distribution.system.domain.converter.AddressNameInfoConverter;
import com.distribution.system.domain.dto.ChoosePhoneDTO;
import com.distribution.system.domain.dto.SendCodeDTO;
import com.distribution.system.domain.entity.AddressChannel;
import com.distribution.system.domain.entity.CmccDaOrder;
import com.distribution.system.domain.entity.CmccDaProduct;
import com.distribution.system.domain.entity.CmccDaUpChannelInfo;
import com.distribution.system.domain.req.ReqResult;
import com.distribution.system.service.AddressChannelService;
import com.distribution.system.service.AliSmsSendService;
import com.distribution.system.service.CmccDaProductService;
import com.distribution.system.service.impl.AliSmsSendServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Liping Huo
 * @date 2023/5/23 2:06
 */
@Slf4j
public abstract class AbstractChannel implements Channel {
    private static final Logger choosePhoneLog = LoggerFactory.getLogger("choosePhoneLog");
    private static final Logger placeOrderLog = LoggerFactory.getLogger("placeOrderLog");

    private final AddressNameInfoConverter addressNameInfoConverter;
    private final CmccDaUpChannelInfoBO cmccDaUpChannelInfoBO;
    protected Map<String,String> interfaceParamsMap;
    protected Map<String,String> interfaceUrlsMap;
    protected String orderId;

    public AbstractChannel(CmccDaUpChannelInfoBO cmccDaUpChannelInfoBO) {
        this.cmccDaUpChannelInfoBO = cmccDaUpChannelInfoBO;
        interfaceParamsMap = getInterfaceParamsMap();
        interfaceUrlsMap = getInterfaceUrlsMap();
        addressNameInfoConverter = SpringUtils.getBean(AddressNameInfoConverter.class);
    }

    @Override
    public CmccDaUpChannelInfoBO getCmccDaChannelInfo() {
        return cmccDaUpChannelInfoBO;
    }

    /**
    * @Author: GodLu
    * @Date: 2024/7/16 11:56
    * @Description: 获取渠道参数
    * @return: Map<String,String>
    */
    protected Map<String,String> getInterfaceParamsMap(){
        Map<String,String> channelParamsMap = new HashMap<>();
        JSONArray channelParamsJsonArray = JSON.parseArray(getCmccDaChannelInfo().getChannelParams());
        for (Object obj : channelParamsJsonArray) {
            JSONObject jsonObj = (JSONObject) obj;
            channelParamsMap.put(jsonObj.getString("key"),jsonObj.getString("value"));
        }
        return channelParamsMap;
    }

    /**
    * @Author: GodLu
    * @Date: 2024/7/16 11:56
    * @Description: 获取渠道接口地址
    * @return: Map<String,String>
    */
    protected Map<String,String> getInterfaceUrlsMap(){
        Map<String,String> channelUrlsMap = new HashMap<>();
        JSONArray channelUrlsJsonArray = JSON.parseArray(getCmccDaChannelInfo().getChannelInterfaceUrl());
        for (Object obj : channelUrlsJsonArray) {
            JSONObject jsonObj = (JSONObject) obj;
            channelUrlsMap.put(jsonObj.getString("key"),jsonObj.getString("value"));
        }
        return channelUrlsMap;
    }

    private AddressInfoBo getAddressInfo(@Valid AddressNameBo addressNameBo, AddressChannelService addressChannelService){
        // 获取收货地址和归属地地址
        AddressInfoBo addressInfoBo = getChannelAddressInfo(addressNameBo, addressChannelService);
        if (addressInfoBo == null){
            addressInfoBo = new AddressInfoBo();
            // 归属地信息
            List<AddressChannel> addressChannelList;
            if (StringUtils.isNotBlank(addressNameBo.getAttributeProvince()) && StringUtils.isNotBlank(addressNameBo.getAttributeCity())){
                addressChannelList = addressChannelService.list(new LambdaQueryWrapper<AddressChannel>()
                        .likeRight(AddressChannel::getProvinceName, addressNameBo.getAttributeProvince().substring(0,2))
                        .likeRight(AddressChannel::getCityName, addressNameBo.getAttributeCity().substring(0,2))
                        .eq(AddressChannel::getChannelId, "0"));
            } else {
                addressChannelList = addressChannelService.list(new LambdaQueryWrapper<AddressChannel>()
                        .likeRight(AddressChannel::getProvinceName, addressNameBo.getAddressProvince().substring(0,2))
                        .likeRight(AddressChannel::getCityName, addressNameBo.getAddressCity().substring(0,2))
                        .eq(AddressChannel::getChannelId, "0"));
            }
            if (addressChannelList == null || addressChannelList.isEmpty()) {
                throw new ServiceException("归属地区划代码异常!");
            }
            AddressChannel attributeInfo = addressChannelList.get(0);
            addressInfoBo.setAttributeInfo(attributeInfo);
            // 收货地信息
            List<AddressChannel> addressChannels = addressChannelService.lambdaQuery()
                    .likeRight(AddressChannel::getProvinceName, addressNameBo.getAddressProvince().substring(0, 2))
                    .likeRight(AddressChannel::getCityName, addressNameBo.getAddressCity().substring(0, 2))
                    .likeRight(AddressChannel::getDistrictName, addressNameBo.getAddressDistrict().substring(0, 2))
                    .eq(AddressChannel::getChannelId, "0").list();
            if (addressChannels == null || addressChannels.isEmpty()) {
                throw new ServiceException("收货地区划代码异常!");
            }else if (addressChannels.size() > 1){
                AddressChannel addressChannel = addressChannels.stream().filter(f -> f.getDistrictName().equals(addressNameBo.getAddressDistrict())).collect(Collectors.toList()).get(0);
                addressInfoBo.setAddressInfo(addressChannel);
            } else {
                addressInfoBo.setAddressInfo(addressChannels.get(0));
            }
        }
        return addressInfoBo;
    }

    /**
     * @param choosePhoneDTO     选号信息
     * @param cmccDaProduct      产品信息
     * @param addressChannelService 地区服务
     * @Author: GodLu
     * @Date: 2024/7/17 11:31
     * @Description: 选号
     * @return: JSONObject
     */
    @Override
    public ReqResult choosePhone(ChoosePhoneDTO choosePhoneDTO, CmccDaProduct cmccDaProduct, AddressChannelService addressChannelService) {
        AddressNameBo addressNameBo = addressNameInfoConverter.choosePhoneDtoToAddressNameBo(choosePhoneDTO);
        AddressInfoBo addressInfoBo = getAddressInfo(addressNameBo, addressChannelService);
        // 发送请求
        String requestJsonStr = configChoosePhoneRequestParams(choosePhoneDTO, cmccDaProduct, addressInfoBo);
        log.info("【{}】选号请求 => {}", getCmccDaChannelInfo().getChannelName(), requestJsonStr);
        choosePhoneLog.info("【{}】选号请求 => {}", getCmccDaChannelInfo().getChannelName(), requestJsonStr);
        String responseJsonStr = sendChoosePhoneRequest(requestJsonStr);
        log.info("【{}】选号响应 => {}", getCmccDaChannelInfo().getChannelName(), responseJsonStr);
        choosePhoneLog.info("【{}】选号响应 => {}", getCmccDaChannelInfo().getChannelName(), responseJsonStr);
        return parseChoosePhoneResponseStr(JSONObject.parseObject(responseJsonStr));
    }
    private static final String NUMBER_CHECK_MAP = "numberCheckMap";
    protected void redisCacheNumberCheckMap(List<String> phoneNumArray, String uuid, JSONArray checkListArray){
        //这里不知道为什么自动注入得到的redis对象为null，所以反射调用
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        //通过redis缓存将Key(phoneNumber + uuid)与Value(check_code)绑定
        Map<String,String> numberCheckMap = new HashMap<>();
        if (checkListArray != null && !checkListArray.isEmpty()) {
            for (int i = 0; i < phoneNumArray.size(); i++) {
                numberCheckMap.put(phoneNumArray.get(i) + uuid, (String) checkListArray.get(i));
            }
            log.info("redis存储Key【{}】Value【{}】", NUMBER_CHECK_MAP, numberCheckMap);
            redisCache.setCacheMap(NUMBER_CHECK_MAP, numberCheckMap);
        }
    }
    protected String getRedisNumberCheck(String choosePhone, String uuid){
        String numberCheck = "";
        //这里不知道为什么自动注入得到的redis对象为null，所以反射调用
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        //通过redis缓存查询number对应的check_code
        Map<String, Object> numberCheckMap = redisCache.getCacheMap(NUMBER_CHECK_MAP);
        log.info("redis取Key【{}】的值为【{}】", NUMBER_CHECK_MAP, numberCheckMap.toString());
        if (!numberCheckMap.isEmpty()) {
            Object checkCodeObj = numberCheckMap.get(choosePhone + uuid);
            numberCheck = checkCodeObj == null ? "" : String.valueOf(checkCodeObj);
        }
        return numberCheck;
    }

    /**
    * @Author: GodLu
    * @Date: 2024/7/16 11:55
    * @Description: 下单
    * @param cmccDaOrder 订单
    * @param cmccDaProduct 产品
    * @param addressChannelService 地区编码服务
    * @return: ReqResult
    */
    @Override
    public ReqResult placeOrder(CmccDaOrder cmccDaOrder, CmccDaProduct cmccDaProduct, AddressChannelService addressChannelService){
        AddressNameBo addressNameBo = addressNameInfoConverter.orderToAddressNameBo(cmccDaOrder);
        AddressInfoBo addressInfoBo = getAddressInfo(addressNameBo, addressChannelService);
        // 如果当前产品需要验证码且是宽带则校验自己的验证码
        if ("1".equals(cmccDaProduct.getCodeFlag()) && "1".equals(cmccDaProduct.getBroadbandFlag())){
            AliSmsSendService aliSmsSendService = SpringUtils.getBean(AliSmsSendService.class);
            ReqResult verifyReqResult = aliSmsSendService.verifySmsCode(cmccDaOrder.getCode(), cmccDaOrder.getCustomerCertNo() + cmccDaOrder.getCustomerPhone());
            if (verifyReqResult.getCode() != 200) return verifyReqResult;
        }
        // 请求json
        String requestJsonStr;
        // 线上产品不需要收货地和归属地信息
        if (StringUtils.equals(cmccDaProduct.getProductCode(), "230817002")){
            // 设置订单归属地址
            cmccDaOrder.setAttributeProvince("河北");
            // 配置请求参数
            requestJsonStr = configPlaceOrderRequestParams(cmccDaOrder, cmccDaProduct, null);
        }else {
            // 设置订单收货地址
            AddressChannel addressInfo = addressInfoBo.getAddressInfo();
            cmccDaOrder.setAddressProvince(addressInfo.getProvinceName());
            cmccDaOrder.setAddressCity(addressInfo.getCityName());
            cmccDaOrder.setAddressArea(addressInfo.getDistrictName());
            cmccDaOrder.setAddress(addressInfo.getProvinceName() + addressInfo.getCityName() + addressInfo.getDistrictName());
            // 设置订单归属地址
            AddressChannel attributeAddressInfo = addressInfoBo.getAttributeInfo();
            cmccDaOrder.setAttributeProvince(attributeAddressInfo.getProvinceName());
            cmccDaOrder.setAttributeCity(attributeAddressInfo.getCityName());
            // 配置请求参数
            requestJsonStr = configPlaceOrderRequestParams(cmccDaOrder, cmccDaProduct, addressInfoBo);
        }
        log.info("【{}】下单请求 => {}", getCmccDaChannelInfo().getChannelName(), requestJsonStr);
        placeOrderLog.info("【{}】下单请求 => {}", getCmccDaChannelInfo().getChannelName(), requestJsonStr);
        // 设置订单的请求json信息
        cmccDaOrder.setRequestJson(requestJsonStr);
        // 发送请求
        String responseJsonStr = sendPlaceOrderRequest(requestJsonStr);
        log.info("【{}】下单响应 => {}", getCmccDaChannelInfo().getChannelName(), responseJsonStr);
        placeOrderLog.info("【{}】下单响应 => {}", getCmccDaChannelInfo().getChannelName(), responseJsonStr);
        // 设置订单的响应json信息
        cmccDaOrder.setResponseJson(responseJsonStr);
        // 解析响应结果
        return parsePlaceOrderResponseStr(JSONObject.parseObject(responseJsonStr));
    }

    /**
    * @Author: GodLu
    * @Date: 2024/7/16 11:55
    * @Description: 发送短信验证码
    * @param unOrderProduct 产品请求对象
    * @param sendCodeDTO 验证码请求对象
    * @return: JSONObject
    */
    @Override
    public ReqResult sendSmsCode(CmccDaProduct unOrderProduct, SendCodeDTO sendCodeDTO) {
        // 如果是宽带则发送自己的验证码
        if ("1".equals(unOrderProduct.getBroadbandFlag())){
            AliSmsSendService aliSmsSendService = SpringUtils.getBean(AliSmsSendService.class);
            return aliSmsSendService.genAndSendAliSmsCode(sendCodeDTO.getCustomerPhone(), sendCodeDTO.getCertNum() + sendCodeDTO.getCustomerPhone());
        }else {
            return sendCardSmsCode(unOrderProduct,sendCodeDTO);
        }
    }

    /**
    * @Author: GodLu
    * @Date: 2024/8/21 11:04
    * @Description: 刷新渠道方商品佣金
    * @param cmccDaUpChannelInfo 渠道方信息
    * @return: void
    */
    public void updateChannelCommission(CmccDaUpChannelInfo cmccDaUpChannelInfo, Map<Integer,String> goodsIdCommissionMap) {
        if (goodsIdCommissionMap.isEmpty()) return;
        CmccDaProductService cmccDaProductService = SpringUtils.getBean(CmccDaProductService.class);
        List<CmccDaProduct> productList = cmccDaProductService.lambdaQuery()
                .eq(CmccDaProduct::getBindChannelInfoId, cmccDaUpChannelInfo.getChannelId())
                .in(CmccDaProduct::getProductParam, goodsIdCommissionMap.keySet())
                .eq(CmccDaProduct::getProductStatus, "1").list();
        for (CmccDaProduct cmccDaProduct : productList) {
            for (Map.Entry<Integer, String> entry : goodsIdCommissionMap.entrySet()) {
                BigDecimal channelCommission = new BigDecimal(entry.getValue());
                log.info("商品【{}】 ===> 渠道佣金【{}】 | 基础佣金【{}】", cmccDaProduct.getProductName(), channelCommission, cmccDaProduct.getBasicsCommission());
                BigDecimal commission = cmccDaProduct.getChannelCommission();
                if (commission == null){
                    commission = channelCommission;
                    cmccDaProductService.lambdaUpdate().eq(CmccDaProduct::getProductParam, entry.getKey())
                            .eq(CmccDaProduct::getBindChannelInfoId, cmccDaUpChannelInfo.getChannelId())
                            .set(CmccDaProduct::getChannelCommission, commission).update();
                }
                BigDecimal subtract = commission.subtract(channelCommission);
                if (subtract.compareTo(BigDecimal.ZERO) != 0) {
                    // 如果渠道佣金比当前商品记录的佣金低了，则短信提醒
                    if (subtract.compareTo(BigDecimal.ZERO) < 0) {
                        AliSmsSendServiceImpl aliSmsSendService = SpringUtils.getBean(AliSmsSendServiceImpl.class);
                        JSONObject paramJson = new JSONObject();
                        paramJson.put("channelName", cmccDaUpChannelInfo.getChannelName());
                        paramJson.put("product", cmccDaProduct.getProductName());
                        paramJson.put("depreciate", subtract);
                        paramJson.put("time", DateUtil.now());
                        aliSmsSendService.sendCommissionDepreciate(cmccDaUpChannelInfo.getNotifyPhone(), paramJson);
                    }
                    // 更新
                    cmccDaProductService.lambdaUpdate().eq(CmccDaProduct::getProductParam, entry.getKey())
                            .eq(CmccDaProduct::getBindChannelInfoId, cmccDaUpChannelInfo.getChannelId())
                            .set(CmccDaProduct::getChannelCommission, channelCommission).update();
                }
            }
        }
    }
}
